/**
 Copyright (C) 2013 Yuyao Liang

 This source code is release under the BSD License.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.

 Created on Sep 30, 2013 10:59:22 AM
 */
package com.googlecode.contourplot;

import java.util.LinkedHashSet;
import java.util.Set;

import org.jfree.data.contour.DefaultContourDataset;

/**
 * @author lianyuy
 * 
 */
@SuppressWarnings("deprecation")
public class ContourPlotDataSeries extends DefaultContourDataset implements
		IContourDataSeries {

	private static final long serialVersionUID = -2598834004111468279L;
	private int xStepSize;
	private int yStepSize;
//	protected Number[] xValues;
//	protected Number[] yValues;
	protected double xmin, ymin, xmax, ymax;

	public ContourPlotDataSeries() {
		super();
	}

	/**
	 * @param seriesKey
	 * @param xData
	 * @param yData
	 * @param zData
	 */
	@SuppressWarnings("rawtypes")
	public ContourPlotDataSeries(Comparable seriesKey, Object[] xData,
			Object[] yData, Object[] zData, int xStepSize, int yStepSize) {
		super(seriesKey, xData, yData, zData);
		this.xStepSize = xStepSize;
		this.yStepSize = yStepSize;

		xValues = getXValuesArray();
		yValues = getYValuesArray();

		xmin = xValues[0].doubleValue();
		ymin = yValues[0].doubleValue();
		xmax = xValues[xValues.length - 1].doubleValue();
		ymax = yValues[yValues.length - 1].doubleValue();
	}

	/**
	 * @return the xStepSize
	 */
	public int getXStepSize() {
		return xStepSize;
	}

	/**
	 * @return the yStepSize
	 */
	public int getYStepSize() {
		return yStepSize;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.googlecode.contourplot.IContourDataSeries#getZValue(double,
	 * double)
	 */
	@Override
	public double getZValue(double x, double y) {
		if (x < xmin || x > xmax || y < ymin || y > ymax)
			return Double.NaN;

		int xindex = (int) ((x - xmin) / ((xmax - xmin) / (xStepSize - 1)));
		int yindex = (int) ((y - ymin) / ((ymax - ymin) / (yStepSize - 1)));

		double value = 0;
		try {
			Number[] zValuesArray = getYValues();
			double v00 = zValuesArray[yindex * xStepSize + xindex]
					.doubleValue();
			double v10 = zValuesArray[yindex * xStepSize + xindex + 1]
					.doubleValue();
			double v01 = zValuesArray[(yindex + 1) * xStepSize + xindex]
					.doubleValue();
			double v11 = zValuesArray[(yindex + 1) * xStepSize + xindex + 1]
					.doubleValue();

			double higherY = yValues[xindex + 1].doubleValue();
			double lowerY = yValues[xindex].doubleValue();

			double higherX = xValues[xindex + 1].doubleValue();
			double lowerX = xValues[xindex].doubleValue();

			double dHy = higherY - y;
			double dLy = y - lowerY;

			double dHx = higherX - x;
			double dLx = x - lowerX;

			double dx = higherX - lowerX;
			double dy = higherY - lowerY;

			value = v00 * dHx * dHy;
			value += v10 * dLx * dHy;
			value += v01 * dHx * dLy;
			value += v11 * dLx * dLy;
			value /= (dx * dy);
		} catch (Exception e) {
			return Double.NaN;
		}
		return value;
	}

	/**
	 * @return
	 */
	private Number[] getYValuesArray() {
		Set<Number> tmp = new LinkedHashSet<Number>();
		for (Number each : getYValues()) {
			tmp.add(each);
		}
		return tmp.toArray(new Number[tmp.size()]);
	}

	/**
	 * @return
	 */
	private Number[] getXValuesArray() {
		Set<Number> tmp = new LinkedHashSet<Number>();
		for (Number each : getXValues()) {
			tmp.add(each);
		}
		return tmp.toArray(new Number[tmp.size()]);
	}

}
